/***************************************************************************

Copyright (c) Microsoft Corporation. All rights reserved.
This code is licensed under the Visual Studio SDK license terms.
THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.

***************************************************************************/

using System;
using System.Collections.Generic;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.TextManager.Interop;
using Microsoft.VisualStudio.Package;
using System.Text.RegularExpressions;
using Wicresoft.Shell.Core;


namespace Babel
{
    public class AuthoringScope : Microsoft.VisualStudio.Package.AuthoringScope
    {
        public AuthoringScope(object parseResult)
        {
            this.parseResult = parseResult;

            // how should this be set?
            this.resolver = new Resolver();
        }

        object parseResult;
        public Resolver resolver;

        // ParseReason.QuickInfo
        public override string GetDataTipText(int line, int col, out TextSpan span)
        {
            span = new TextSpan();
            return null;
        }

        // ParseReason.CompleteWord
        // ParseReason.DisplayMemberList
        // ParseReason.MemberSelect
        // ParseReason.MemberSelectAndHilightBraces
        public override Microsoft.VisualStudio.Package.Declarations GetDeclarations(IVsTextView view, int line, int col, TokenInfo info, ParseReason reason)
        {
            IList<Declaration> declarations;
            string currentCommand;
            int hResult = view.GetTextStream(line, info.StartIndex, line, info.EndIndex + 1, out currentCommand);

            if (info.Token == (int)Babel.Parser.Tokens.DOT)
            {            
                string TextAboveCurrentDot;
                view.GetTextStream(0, 0, line, info.EndIndex, out TextAboveCurrentDot);
                //parse the context to store the local variable
                IntelliSenseManager.ParseContext(TextAboveCurrentDot,false);

                List<Babel.Declaration> members = new List<Declaration>();
                //get the current line text
                string lineText;
                view.GetTextStream(line, 0, line, info.EndIndex, out lineText);
                if (lineText != null)
                {
                    lineText = lineText.Replace("{", "").Replace("}", "").Replace(" ", "");
                    //get the last right expression
                    string IdetifierPattern = @"([a-zA-Z][a-zA-Z0-9\-_]*)";
                    string rightExpressionPattern = string.Format(@"\${0}+(\.{0}*(\(.*\))*)*", IdetifierPattern);
                    MatchCollection mc2 = Regex.Matches(lineText, rightExpressionPattern);
                    string finaltype;
                    if (mc2.Count > 0)
                    {
                        string expression = mc2[mc2.Count - 1].Value;
                        finaltype = IntelliSenseManager.GetExpressionType(expression);
                    }
                    else
                    {
                        finaltype = "void";
                    }
                    //int indexofdollar = lineText.LastIndexOf('$');
                    //string expression = lineText.Substring(indexofdollar, lineText.Length - indexofdollar).Replace("{", "").Replace("}", "").Replace(" ", "");
                    //finaltype = this.GetFinalType(expression);

                    foreach (UmcTypeProperty utp in UmcReflector.GetProperties(finaltype))
                    {
                        members.Add(new Declaration(string.Format("{0} {1}\n{2}", utp.TypeName, utp.PropertyName, utp.PropertyDescription),
                            utp.PropertyName,
                            (int)IconImageIndex.Property + (int)IconImageIndex.AccessPublic,
                            utp.PropertyName));
                    }

                    foreach (UmcTypeMethod utm in UmcReflector.GetMethods(finaltype))
                    {
                        members.Add(new Declaration(string.Format("{0} {1}({2})\n{3}",
                            utm.MethodReturnTypeName, utm.MethodName, utm.MethodParam, utm.MethodDescription),
                            utm.MethodName,
                            (int)IconImageIndex.Method + (int)IconImageIndex.AccessPublic,
                            utm.MethodName));
                    }
                }
                declarations = members;
            }
            else if (info.Token == (int)Babel.Parser.Tokens.DOLLAR)
            {
                string TextAboveCurrentDot;
                view.GetTextStream(0, 0, line, info.EndIndex, out TextAboveCurrentDot);
                IntelliSenseManager.ParseContext(TextAboveCurrentDot,false);


                List<Babel.Declaration> members = new List<Declaration>();

                foreach (KeyValuePair<string, UmcVariable> uv in IntelliSenseManager.GetVariables())
                {
                    members.Add(new Declaration(string.Format("{0} ${1}", uv.Value.VariableType, uv.Value.VariableName),
                             string.Format("${0}", uv.Value.VariableName),
                             (int)IconImageIndex.Field + (int)IconImageIndex.AccessPrivate,
                             string.Format("${0}", uv.Value.VariableName)
                             ));
                }
                declarations = members;
            }
            else if (info.Token == (int)Babel.Parser.Tokens.LCURLY)
            {
                view.ReplaceTextOnLine(line, info.StartIndex + 1, 0, "}", 1);
                declarations = new List<Declaration>();
            }
            else if (info.Token == (int)Babel.Parser.Tokens.LBRACKET)
            {
                view.ReplaceTextOnLine(line, info.StartIndex + 1, 0, "]", 1);
                declarations = new List<Declaration>();
            }
            else if (info.Token == (int)Babel.Parser.Tokens.LPAREN)
            {
                view.ReplaceTextOnLine(line, info.StartIndex + 1, 0, ")", 1);
                declarations = new List<Declaration>();
            }
            else if (info.Token == (int)Babel.Parser.Tokens.DQUOTE)
            {
                view.ReplaceTextOnLine(line, info.StartIndex + 1, 0, "\"", 1);
                declarations = new List<Declaration>();
            }
            else if (info.Token == (int)Babel.Parser.Tokens.SQUOTE)
            {
                view.ReplaceTextOnLine(line, info.StartIndex + 1, 0, "'", 1);
                declarations = new List<Declaration>();
            }
            else if (info.Token == (int)Babel.Parser.Tokens.EDTAG1)
            {
                string quto="\"";
                string semiMarkupPattern = string.Format(@"<\w+([ \r\n\t]+\w+[ \r\n\t]*=[ \r\n\t]*\{0}[^\r\n\{0}]*\{0})*[ \r\n\t]*>", quto);
                string contextAbove;
                view.GetTextStream(0, 0, line, info.EndIndex+1, out contextAbove);
                MatchCollection mc2 = Regex.Matches(contextAbove, semiMarkupPattern);
                if (mc2.Count > 0)
                {
                    string va = mc2[mc2.Count - 1].Value;
                    string[] array = va.Split(' ');
                    string replace;
                    if (array.Length > 1)
                    {
                        replace = string.Format("</{0}>", array[0].Substring(1, array[0].Length - 1));
                    }
                    else
                    {
                        replace = string.Format("</{0}>", array[0].Substring(1, array[0].Length - 2));
                    }
                    view.ReplaceTextOnLine(line, info.StartIndex + 1, 0, replace, replace.Length);
                }

                declarations = new List<Declaration>();
            }
            else
            {

                switch (reason)
                {
                    case ParseReason.CompleteWord:
                        declarations = resolver.FindCompletions(currentCommand, line, col);
                        break;
                    case ParseReason.DisplayMemberList:
                        declarations = resolver.FindMembers(info, line, col);
                        break;
                    case ParseReason.MemberSelect:
                        declarations = resolver.FindMembers(info, line, col);
                        break;
                    case ParseReason.MemberSelectAndHighlightBraces:
                        declarations = resolver.FindMembers(info, line, col);
                        break;
                    default:
                        throw new ArgumentException("reason");
                }
            }


            return new Declarations(declarations);
        }

        // ParseReason.GetMethods
        public override Microsoft.VisualStudio.Package.Methods GetMethods(int line, int col, string name)
        {
            //return new Methods(resolver.FindMethods(parseResult, line, col, name));
                        /*
            public struct Method
            {
                public string Name;
                public string Description;
                public string Type;
                public IList<Parameter> Parameters;
            }

            public struct Parameter
            {
                public string Name;
                public string Display;
                public string Description;
            }
             */

            List<Method> methods = new List<Method>();
            string prefix = name.Substring(0,name.LastIndexOf('.'));
            string type = IntelliSenseManager.GetExpressionType(prefix);
            string methodName = name.Replace(prefix,"").Replace(".","");
            foreach (UmcTypeMethod utm in UmcReflector.GetMethods(type))
            {
                if (utm.MethodName == methodName)
                {
                    List<Parameter> param = new List<Parameter>();
                    foreach(string p in utm.Params)
                    {
                        param.Add(new Parameter()
                            {
                                Name = p,
                                Display = p,
                                Description = ""
                            }
                        );
                    }

                    methods.Add(new Method()
                        {
                            Name = utm.MethodName,
                            Description = utm.MethodDescription,
                            Type = utm.MethodReturnTypeName,
                            Parameters = param
                        }
                    );
                }
            }


            return new Methods(methods);

        }

        // ParseReason.Goto
        public override string Goto(VSConstants.VSStd97CmdID cmd, IVsTextView textView, int line, int col, out TextSpan span)
        {
            // throw new System.NotImplementedException();
            span = new TextSpan();
            return null;
        }
    }
}
